import { Injectable, Logger } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { VipStatusEntity } from "../entities/vip-status.entity";
import { CharacterService } from "./character.service";
import { InventoryService } from "./inventory.service";
import { DeputyGeneralService } from "./deputy-general.service";
import { GemService } from "./gem.service";
import { VipRewardConfigEntity } from "../entities/vip-reward-config.entity";
import { DataSource } from "typeorm";
import { CharacterInventoryEntity } from "../entities/character-inventory.entity";
import { BasicItemEntity } from "../entities/basic-item.entity";
import { CharacterGemInventoryEntity } from "../entities/character-gem-inventory.entity";
import { GemBaseEntity } from "../entities/gem-base.entity";
import { DeputyGeneral } from "../entities/deputy-general.entity";
import { DeputyGeneralBase } from "../entities/deputy-general-base.entity";
import { PlayerDeputy } from "../entities/player-deputy.entity";
import { PlayerDeputyWarehouse } from "../entities/player-deputy-warehouse.entity";
// import removed: CharacterMedicineService 不再用于 VIP 物品发放

interface VipPrivilegeItem {
  id: number;
  type: number; // 0:特权说明 1:物品 2:经验 3:宝石 4:副将 ...
  title: string;
  state: number; // 0可领取 1已领取 2已获得（展示）
  choose?: number; // 是否可选择
}

@Injectable()
export class VipService {
  private readonly logger = new Logger(VipService.name);

  constructor(
    @InjectRepository(VipStatusEntity)
    private readonly vipRepository: Repository<VipStatusEntity>,
    @InjectRepository(VipRewardConfigEntity)
    private readonly vipRewardRepository: Repository<VipRewardConfigEntity>,
    private readonly characterService: CharacterService,
    private readonly inventoryService: InventoryService,
    private readonly deputyGeneralService: DeputyGeneralService,
    private readonly gemService: GemService,
    private readonly dataSource: DataSource
  ) {}

  private getToday(): string {
    const now = new Date();
    return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(
      2,
      "0"
    )}-${String(now.getDate()).padStart(2, "0")}`;
  }

  async ensureVipRow(characterId: number): Promise<VipStatusEntity> {
    let row = await this.vipRepository.findOne({ where: { characterId } });
    if (!row) {
      row = this.vipRepository.create({
        characterId,
        vipLevel: -1,
        vipExp: 0,
        dailyClaimDate: null,
        created_at: new Date(),
        updated_at: new Date(),
      });
      await this.vipRepository.save(row);
    }
    return row;
  }

  // 领取记录表：vip_claim_records(characterId,lvl,pid,type,claimed_at)
  private async ensureClaimTable() {
    const sql = `CREATE TABLE IF NOT EXISTS vip_claim_records (
      id INT NOT NULL AUTO_INCREMENT,
      characterId INT NOT NULL,
      lvl INT NOT NULL,
      pid INT NOT NULL,
      type INT NOT NULL,
      claimed_at DATETIME NOT NULL,
      PRIMARY KEY (id),
      UNIQUE KEY uniq_claim (characterId,lvl,pid,type)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4`;
    await this.vipRepository.manager.query(sql);
  }

  private async hasClaimed(
    characterId: number,
    lvl: number,
    pid: number,
    type: number
  ): Promise<boolean> {
    await this.ensureClaimTable();
    const rows = await this.vipRepository.manager.query(
      `SELECT 1 FROM vip_claim_records WHERE characterId=? AND lvl=? AND pid=? AND type=? LIMIT 1`,
      [characterId, lvl, pid, type]
    );
    return rows && rows.length > 0;
  }

  private async markClaimed(
    characterId: number,
    lvl: number,
    pid: number,
    type: number
  ) {
    await this.ensureClaimTable();
    await this.vipRepository.manager.query(
      `INSERT IGNORE INTO vip_claim_records(characterId,lvl,pid,type,claimed_at) VALUES (?,?,?,?,NOW())`,
      [characterId, lvl, pid, type]
    );
  }

  // 6102：查询VIP信息
  async queryVipInfo(characterId: number, lvl: number) {
    const row = await this.ensureVipRow(characterId);
    const vipLvl = row.vipLevel ?? -1;
    const maxLvl = 9;
    // 视图等级：当 lvl=-2 时，展示“当前 VIP 等级”的视图（非VIP 视为 0）
    const viewLvl = lvl === -2 ? Math.max(0, vipLvl) : lvl;
    // next: 升级到“视图等级(viewLvl)”还需要的经验 = 需要经验(到该等级的累计) - 已注入经验
    const currentTotalExp = row.vipExp || 0;
    const needTotal = viewLvl >= 0 ? this.getTotalRequiredExp(viewLvl) : 0;
    const next = Math.max(0, needTotal - currentTotalExp);
    let list: VipPrivilegeItem[] = await this.getVipPrivilegeListFromDb(
      viewLvl
    );
    // 规则：查看任意 lvl，若 vipLvl >= lvl，则奖励类(1/2/3/4)可领取(0)；若已领取，标 1；否则展示(2)
    if (viewLvl >= 0) {
      const enriched = await Promise.all(
        list.map(async (it) => {
          if (![1, 2, 3, 4].includes(it.type)) return it;
          // 未达等级：不显示按钮（0）
          if (vipLvl < viewLvl) return { ...it, state: 0 };
          const pid = it.id || 0;
          const claimed = await this.hasClaimed(
            characterId,
            viewLvl,
            pid,
            it.type
          );
          // 前端规则：1=显示“领取”按钮，2=已领取文字
          return { ...it, state: claimed ? 2 : 1 };
        })
      );
      list = enriched;
    }
    return {
      hpBag: "无",
      list,
      maxLvl,
      next,
      vipLvl,
    };
  }

  // 61020：消耗金砖注入 vip 经验（1砖=1exp）
  async addVipExp(characterId: number, amount: number) {
    const row = await this.ensureVipRow(characterId);
    row.vipExp += amount;
    // 升级判定（示例：每等级需要 100,500,1000,... 这里使用文档中的 next 取值）
    while (
      row.vipLevel < 9 &&
      row.vipExp >= this.getTotalRequiredExp(row.vipLevel + 1)
    ) {
      row.vipLevel += 1;
    }
    row.updated_at = new Date();
    await this.vipRepository.save(row);
    return { vipLvl: row.vipLevel, vipExp: row.vipExp };
  }

  // 重置 VIP（测试用）
  async resetVip(characterId: number) {
    const row = await this.ensureVipRow(characterId);
    row.vipLevel = -1;
    row.vipExp = 0;
    row.dailyClaimDate = null;
    row.updated_at = new Date();
    await this.vipRepository.save(row);
    return { success: true };
  }

  // 6153：VIP 领取每日在线经验/或一次性物品
  async claimVipReward(
    characterId: number,
    payload: { pid?: number; t: number; lvl: number; dl?: number }
  ) {
    const { pid = 0, t, lvl, dl } = payload;
    const row = await this.ensureVipRow(characterId);
    if (lvl > row.vipLevel) {
      return { code: -1, msg: "VIP等级不足，无法领取" };
    }

    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();
    try {
      // t: 0=特权说明 1=物品 2=经验 3=宝石 4=副将
      if (t === 0) {
        await queryRunner.commitTransaction();
        return { code: 0, msg: "特权生效中", data: true };
      }

      // 事务内防重复：按奖励类型分别归一 pid（确保不同 VIP 等级可各领一次）
      await this.ensureClaimTable();

      if (t === 1) {
        // 物品：使用 itemId 作为 pid 去重
        const dup = await queryRunner.manager.query(
          `SELECT 1 FROM vip_claim_records WHERE characterId=? AND lvl=? AND pid=? AND type=? LIMIT 1`,
          [characterId, lvl, pid, t]
        );
        if (dup && dup.length > 0) {
          await queryRunner.rollbackTransaction();
          return { code: 8, msg: "已领取" };
        }
        if (pid <= 0) {
          await queryRunner.rollbackTransaction();
          return { code: -1, msg: "物品ID无效" };
        }
        // 数量：优先表配置
        const cfg = await this.vipRewardRepository.findOne({
          where: { vipLevel: lvl, type: 1, itemId: pid, status: 1 },
        });
        let qty = cfg?.quantity && cfg.quantity > 0 ? cfg.quantity : 1;
        // 若无配置尝试从标题解析
        if (!cfg) {
          const list = await this.getVipPrivilegeListFromDb(lvl);
          const entry = list.find((x) => x.type === 1 && x.id === pid);
          const m = entry?.title.match(/\((\d+)\)/);
          if (m && m[1]) {
            const n = parseInt(m[1], 10);
            if (!Number.isNaN(n) && n > 0) qty = n;
          }
        }

        // 发物品到 character_inventory（事务内）
        const item = await queryRunner.manager.findOne(BasicItemEntity, {
          where: { id: pid, status: 1 },
        });
        if (!item) throw new Error("物品不存在");
        // 优先更新已激活的记录
        const existActive = await queryRunner.manager.findOne(
          CharacterInventoryEntity,
          { where: { characterId, itemId: pid, status: 1 } }
        );
        if (existActive) {
          const currentNum = Number((existActive as any).num || 0);
          await queryRunner.manager.update(
            CharacterInventoryEntity,
            { id: (existActive as any).id },
            {
              num: currentNum + qty,
              updated_at: new Date(),
            }
          );
        } else {
          // 再找任意一条记录，激活并累加
          const existAny = await queryRunner.manager.findOne(
            CharacterInventoryEntity,
            { where: { characterId, itemId: pid } }
          );
          if (existAny) {
            const currentNum = Number((existAny as any).num || 0);
            await queryRunner.manager.update(
              CharacterInventoryEntity,
              { id: (existAny as any).id },
              {
                num: currentNum + qty,
                status: 1,
                name: item.name,
                itemType: item.lv,
                pic: item.pic,
                description: item.description,
                level: item.lv,
                rarity: 1,
                obtainedAt: new Date(),
                updated_at: new Date(),
              }
            );
          } else {
            await queryRunner.manager.insert(CharacterInventoryEntity, {
              characterId,
              itemId: pid,
              name: item.name,
              itemType: item.lv,
              num: qty,
              status: 1,
              pic: item.pic,
              description: item.description,
              level: item.lv,
              rarity: 1,
              obtainedAt: new Date(),
              created_at: new Date(),
              updated_at: new Date(),
            });
          }
        }

        // 标记领取（事务内）
        // 读取最新数量
        const afterRow = await queryRunner.manager.findOne(
          CharacterInventoryEntity,
          { where: { characterId, itemId: pid } }
        );
        const afterNum = Number((afterRow as any)?.num || 0);

        await queryRunner.manager.query(
          `INSERT IGNORE INTO vip_claim_records(characterId,lvl,pid,type,claimed_at) VALUES (?,?,?,?,NOW())`,
          [characterId, lvl, pid, t]
        );
        await queryRunner.commitTransaction();
        return {
          code: 0,
          msg: "物品已发放",
          data: { pid, qty, after: afterNum },
        };
      }

      if (t === 2) {
        // 每日在线经验领取（一次/日，任一 VIP 等级领取即视为今日已领）
        // 条件：在线满30分钟
        // 从 ws 层已校验在线时长，这里再次调用 characterService 或者直接不校验（为安全继续校验）
        const minutes = await (
          this.characterService as any
        ).playerOnlineTimeService?.getTodayOnlineMinutes?.(characterId);
        if (minutes == null || minutes < 30) {
          await queryRunner.rollbackTransaction();
          return { code: -1, msg: "在线不足30分钟，无法领取" };
        }

        // 幂等：检查今日是否有任意等级的 type=2 领取记录
        const today = new Date().toISOString().slice(0, 10);
        const dupDaily = await queryRunner.manager.query(
          `SELECT 1 FROM vip_claim_records WHERE characterId=? AND type=2 AND DATE(claimed_at)=? LIMIT 1`,
          [characterId, today]
        );
        if (dupDaily && dupDaily.length > 0) {
          await queryRunner.rollbackTransaction();
          return { code: 8, msg: "今日已领取VIP在线经验" };
        }

        // 计算本次应得经验：按传入lvl对应配置
        const cfg = await this.vipRewardRepository.findOne({
          where: { vipLevel: lvl, type: 2, status: 1 },
        });
        const gain = cfg?.expAmount ?? 10000;

        await this.characterService.applyExperience(characterId, gain, {
          queryRunner,
        });

        // 记录领取：仍保留唯一键(characterId,lvl,pid,type)，同时允许同日不同lvl只记一条
        await queryRunner.manager.query(
          `INSERT IGNORE INTO vip_claim_records(characterId,lvl,pid,type,claimed_at) VALUES (?,?,?,?,NOW())`,
          [characterId, lvl, 0, t]
        );
        await queryRunner.commitTransaction();
        return { code: 0, msg: `获得经验 ${gain}`, data: true };
      }

      if (t === 3) {
        // 宝石（事务内生成：固定等级=10，属性随机）
        const cfg = await this.vipRewardRepository.findOne({
          where: { vipLevel: lvl, type: 3, status: 1 },
        });
        const claimPid = cfg?.id || 0; // 使用配置主键作为 pid 去重
        const dup = await queryRunner.manager.query(
          `SELECT 1 FROM vip_claim_records WHERE characterId=? AND lvl=? AND pid=? AND type=? LIMIT 1`,
          [characterId, lvl, claimPid, t]
        );
        if (dup && dup.length > 0) {
          await queryRunner.rollbackTransaction();
          return { code: 8, msg: "已领取" };
        }
        const gemLevel = 10; // 需求：随机10级宝石一颗（等级固定为10）
        await this.gemService.awardRandomGemWithLevel(
          queryRunner,
          characterId,
          gemLevel
        );

        const gemAfterCountRow = await queryRunner.manager
          .createQueryBuilder(CharacterGemInventoryEntity, "g")
          .where("g.character_id = :cid AND g.status = 1", { cid: characterId })
          .getCount();
        await queryRunner.manager.query(
          `INSERT IGNORE INTO vip_claim_records(characterId,lvl,pid,type,claimed_at) VALUES (?,?,?,?,NOW())`,
          [characterId, lvl, claimPid, t]
        );
        await queryRunner.commitTransaction();
        return {
          code: 0,
          msg: `宝石奖励已发放(10级, 随机属性)`,
          data: { total: gemAfterCountRow },
        };
      }

      if (t === 4) {
        // 副将（事务内生成）
        // 品质：优先表配置
        let starLevel = 1;
        const cfg = await this.vipRewardRepository.findOne({
          where: { vipLevel: lvl, type: 4, status: 1 },
        });
        const claimPid = cfg?.id || 0; // 使用配置主键作为 pid 去重
        const dup = await queryRunner.manager.query(
          `SELECT 1 FROM vip_claim_records WHERE characterId=? AND lvl=? AND pid=? AND type=? LIMIT 1`,
          [characterId, lvl, claimPid, t]
        );
        if (dup && dup.length > 0) {
          await queryRunner.rollbackTransaction();
          return { code: 8, msg: "已领取" };
        }
        if (cfg?.deputyStar) starLevel = cfg.deputyStar;
        else if (lvl === 1) starLevel = 3;
        else if (lvl === 2) starLevel = 2;
        else starLevel = 1;

        const bases = await queryRunner.manager.find(DeputyGeneralBase, {
          where: { star_level: starLevel },
        });
        if (!bases || bases.length === 0) {
          await queryRunner.rollbackTransaction();
          return { code: -1, msg: "没有可用的基础副将数据" };
        }
        const basePick = bases[Math.floor(Math.random() * bases.length)];
        const deputy = new DeputyGeneral();
        (deputy as any).base_id = (basePick as any).id;
        deputy.czl = 1.0 as any;
        deputy.sp = 10;
        deputy.ap = 10;
        deputy.hp = 10;
        deputy.mp = 10;
        deputy.sp_points = 0;
        deputy.ap_points = 0;
        deputy.hp_points = 0;
        deputy.mp_points = 0;
        deputy.loyalty = 100;
        deputy.compatibility = 0;
        deputy.is_real = true as any;
        deputy.trans_count = 0;
        deputy.roleType = Math.floor(Math.random() * 3) + 1;
        deputy.star = 0;
        deputy.lvl = 0;
        deputy.exp = 100 as any;
        deputy.ultimate_skill_1_id = null as any;
        deputy.ultimate_skill_1_level = 0;
        deputy.ultimate_skill_2_id = null as any;
        deputy.ultimate_skill_2_level = 0;
        deputy.created_at = new Date();
        deputy.updated_at = new Date();
        const saved = await queryRunner.manager.save(DeputyGeneral, deputy);

        // 入玩家副将或仓库
        const count = await queryRunner.manager.count(PlayerDeputy, {
          where: { player_id: characterId },
        });
        if (count >= 10) {
          await queryRunner.manager.insert(PlayerDeputyWarehouse, {
            player_id: characterId,
            deputy_id: (saved as any).id,
          });
        } else {
          await queryRunner.manager.insert(PlayerDeputy, {
            player_id: characterId,
            deputy_id: (saved as any).id,
            pos: 0,
          });
        }

        // 设置等级
        let targetDeputyLevel =
          typeof dl === "number" && dl >= 0 ? dl : cfg?.deputyLevel ?? 0;
        if (targetDeputyLevel > 0) {
          await queryRunner.manager.update(
            DeputyGeneral,
            { id: (saved as any).id },
            { lvl: targetDeputyLevel }
          );
        }

        await queryRunner.manager.query(
          `INSERT IGNORE INTO vip_claim_records(characterId,lvl,pid,type,claimed_at) VALUES (?,?,?,?,NOW())`,
          [characterId, lvl, claimPid, t]
        );
        const depCount = await queryRunner.manager
          .createQueryBuilder(PlayerDeputy, "pd")
          .where("pd.player_id = :pid", { pid: characterId })
          .getCount();
        await queryRunner.commitTransaction();
        return {
          code: 0,
          msg: "副将奖励已发放",
          data: { deputy_id: (saved as any).id, total: depCount },
        };
      }

      await queryRunner.rollbackTransaction();
      return { code: -1, msg: "不支持的奖励类型" };
    } catch (error: any) {
      await queryRunner.rollbackTransaction();
      this.logger.error("VIP领取失败:", error);
      const msg = String(error?.message || error || "");
      // 更友好的提示：数据库死锁/锁等待超时 → 提示稍后重试
      if (
        error?.code === "ER_LOCK_DEADLOCK" ||
        error?.errno === 1213 ||
        /Deadlock found/i.test(msg) ||
        error?.code === "ER_LOCK_WAIT_TIMEOUT" ||
        error?.errno === 1205 ||
        /Lock wait timeout exceeded/i.test(msg)
      ) {
        return { code: -1, msg: "当前领取人数较多，请稍后重试" };
      }
      return { code: -1, msg: "领取失败，请稍后再试" };
    } finally {
      await queryRunner.release();
    }
  }

  // 仅用于回退：不同 vip 等级下的展示项（待移除）
  private getVipPrivilegeList(lvl: number): VipPrivilegeItem[] {
    if (lvl === -2 || lvl === 0) {
      return [
        {
          id: 0,
          state: 0,
          title: "无视目前级别，可设置 20 级以内副将参战",
          type: 0,
        },
        {
          id: 0,
          state: 0,
          title: "授权气血石使用 1 天(每次与野怪战斗结束参战成员自动补满气血)",
          type: 0,
        },
        { id: 0, state: 0, title: "每天可使用 50 次挂机次数", type: 0 },
      ];
    }
    if (lvl === 1) {
      return [
        { id: 1, state: 2, title: "20 级随机英才 1 名", type: 4, choose: 0 },
        { id: 0, state: 0, title: "无视级别限制进行自由交易", type: 0 },
        { id: 0, state: 0, title: "无视目前级别，立即开启挖宝玩法", type: 0 },
        {
          id: 0,
          state: 0,
          title: "授权气血石使用 2 天(每次与野怪战斗结束参战成员自动补满气血)",
          type: 0,
        },
        { id: 0, state: 0, title: "每天可使用 100 次挂机次数", type: 0 },
      ];
    }
    if (lvl === 2) {
      return [
        { id: 2, state: 2, title: "0 级随机将才 1 名", type: 4, choose: 0 },
        {
          id: 0,
          state: 0,
          title: "获得非战斗时自动逐步恢复气血的能力",
          type: 0,
        },
        { id: 0, state: 0, title: "无视目前级别，立即开启当铺功能", type: 0 },
        {
          id: 0,
          state: 0,
          title: "无视目前级别，可直接率领 2 名副将参战",
          type: 0,
        },
        {
          id: 0,
          state: 0,
          title: "得到副将指挥旗(打怪升级时参战常人副将经验值加倍)",
          type: 0,
        },
        {
          id: 0,
          state: 0,
          title: "授权气血石使用 3 天(每次与野怪战斗结束参战成员自动补满气血)",
          type: 0,
        },
        { id: 0, state: 0, title: "每天可使用 150 次挂机次数", type: 0 },
      ];
    }
    if (lvl === 3) {
      return [
        { id: 0, state: 1, title: "10000 经验值", type: 2 },
        { id: 3, state: 2, title: "0 级随机国士 1 名", type: 4 },
        { id: 147, state: 2, title: "初级副将心法(30)", type: 1 },
        {
          id: 0,
          state: 0,
          title: "得到死士令(玩家的常人副将和英才都不再每天自动掉忠诚)",
          type: 0,
        },
        { id: 0, state: 0, title: "无视目前级别，立即开启娱乐场功能", type: 0 },
        {
          id: 0,
          state: 0,
          title: "无视目前级别，可直接率领 30 级以内的副将参战",
          type: 0,
        },
        { id: 0, state: 0, title: "获得周末教军场军训半价优惠特权", type: 0 },
        { id: 0, state: 0, title: "授权气血石使用 5 天", type: 0 },
        { id: 0, state: 0, title: "战斗中可加速 2 倍", type: 0 },
        { id: 0, state: 0, title: "每天可使用 200 次挂机次数", type: 0 },
      ];
    }
    if (lvl === 4) {
      return [
        { id: 0, state: 0, title: "20000 经验值", type: 2 },
        { id: 5, state: 0, title: "自选国士 1 名", type: 4, choose: 1 },
        {
          id: 0,
          state: 0,
          title: "得到英才指挥旗(打怪时参战英才经验值加倍)",
          type: 0,
        },
        { id: 0, state: 0, title: "得到主将打怪基础经验值增加 10%", type: 0 },
        {
          id: 0,
          state: 0,
          title: "无视目前级别，可直接率领 3 名副将参战",
          type: 0,
        },
        {
          id: 0,
          state: 0,
          title: "无视目前级别，可直接率领 40 级以内的副将参战",
          type: 0,
        },
        { id: 0, state: 0, title: "授权气血石使用 10 天", type: 0 },
        { id: 0, state: 0, title: "每天可使用 250 次挂机次数", type: 0 },
        { id: 0, state: 0, title: "每天发起 PK 次数上限提升至 5 次", type: 0 },
      ];
    }
    if (lvl === 5) {
      return [
        { id: 0, state: 0, title: "30000 经验值", type: 2 },
        { id: 7, state: 0, title: "自选国士 1 名", type: 4, choose: 1 },
        { id: 147, state: 0, title: "初级副将心法(50)", type: 1 },
        { id: 257, state: 0, title: "制裁之刃(1)", type: 1 },
        {
          id: 0,
          state: 0,
          title: "得到参战副将打怪基础经验值增加 10%",
          type: 0,
        },
        { id: 0, state: 0, title: "授权气血石增加使用 15 天", type: 0 },
        { id: 0, state: 0, title: "战斗中可加速 3 倍", type: 0 },
        { id: 0, state: 0, title: "无限制使用挂机次数", type: 0 },
        { id: 0, state: 0, title: "每天发起 PK 次数上限提升至 8 次", type: 0 },
      ];
    }
    if (lvl === 6) {
      return [
        { id: 0, state: 0, title: "30000 经验值", type: 2 },
        { id: 0, state: 0, title: "随机 10 级宝石一颗", type: 3 },
        { id: 10, state: 0, title: "自选国士 1 名", type: 4, choose: 1 },
        { id: 148, state: 0, title: "高级副将心法(30)", type: 1 },
        { id: 408, state: 0, title: "蓝波球(1)", type: 1 },
        { id: 257, state: 0, title: "制裁之刃(1)", type: 1 },
        { id: 0, state: 0, title: "可以使用合成 1-7 级宝石功能特权", type: 0 },
        {
          id: 0,
          state: 0,
          title: "无视目前级别，可直接率领 50 级以内的副将参战",
          type: 0,
        },
        { id: 0, state: 0, title: "授权气血石增加使用 30 天", type: 0 },
        { id: 0, state: 0, title: "每天发起 PK 次数上限提升至 10 次", type: 0 },
      ];
    }
    if (lvl === 7) {
      return [
        { id: 0, state: 0, title: "30000 经验值", type: 2 },
        { id: 0, state: 0, title: "随机 10 级宝石一颗", type: 3 },
        { id: 15, state: 0, title: "自选国士 1 名", type: 4, choose: 1 },
        { id: 148, state: 0, title: "高级副将心法(50)", type: 1 },
        { id: 408, state: 0, title: "蓝波球(1)", type: 1 },
        { id: 257, state: 0, title: "制裁之刃(1)", type: 1 },
        { id: 0, state: 0, title: "可以使用合成 1-8 级宝石功能特权", type: 0 },
        {
          id: 0,
          state: 0,
          title: "无视目前级别，可直接率领 60 级以内的副将参战",
          type: 0,
        },
        { id: 0, state: 0, title: "授权气血石增加使用 40 天", type: 0 },
        { id: 0, state: 0, title: "战斗中可加速 5 倍", type: 0 },
        { id: 0, state: 0, title: "每天发起 PK 次数上限提升至 15 次", type: 0 },
      ];
    }
    if (lvl === 8) {
      return [
        { id: 0, state: 0, title: "30000 经验值", type: 2 },
        { id: 0, state: 0, title: "随机 10 级宝石一颗", type: 3 },
        { id: 20, state: 0, title: "自选国士 1 名", type: 4, choose: 1 },
        { id: 149, state: 0, title: "特级副将心法(50)", type: 1 },
        { id: 408, state: 0, title: "蓝波球(1)", type: 1 },
        { id: 257, state: 0, title: "制裁之刃(1)", type: 1 },
        { id: 409, state: 0, title: "转生丹(1)", type: 1 },
        { id: 603, state: 0, title: "小哥哥虎符(10)", type: 1 },
        { id: 0, state: 0, title: "可以使用合成 1-9 级宝石功能特权", type: 0 },
        {
          id: 0,
          state: 0,
          title: "无视目前级别，可直接率领 70 级以内的副将参战",
          type: 0,
        },
        { id: 0, state: 0, title: "授权气血石增加使用 50 天", type: 0 },
        { id: 0, state: 0, title: "战斗中可加速 8 倍", type: 0 },
      ];
    }
    if (lvl === 9) {
      return [
        { id: 0, state: 0, title: "30000 经验值", type: 2 },
        { id: 0, state: 0, title: "随机 10 级宝石一颗", type: 3 },
        { id: 26, state: 0, title: "自选国士 1 名", type: 4, choose: 1 },
        { id: 149, state: 0, title: "特级副将心法(80)", type: 1 },
        { id: 408, state: 0, title: "蓝波球(1)", type: 1 },
        { id: 257, state: 0, title: "制裁之刃(2)", type: 1 },
        { id: 409, state: 0, title: "转生丹(1)", type: 1 },
        { id: 602, state: 0, title: "小姐姐虎符(10)", type: 1 },
        { id: 0, state: 0, title: "可以使用合成 1-10 级宝石功能特权", type: 0 },
        {
          id: 0,
          state: 0,
          title: "无视目前级别，可直接率领 80 级以内的副将参战",
          type: 0,
        },
        { id: 0, state: 0, title: "授权气血石增加使用 60 天", type: 0 },
        { id: 0, state: 0, title: "战斗中可加速 10 倍", type: 0 },
      ];
    }
    return [];
  }

  private async getVipPrivilegeListFromDb(
    lvl: number
  ): Promise<VipPrivilegeItem[]> {
    if (lvl < 0) {
      // 非VIP或特殊视图：用静态0级特权
      return this.getVipPrivilegeList(0);
    }

    const rows = await this.vipRewardRepository.find({
      where: { vipLevel: lvl, status: 1 },
      order: { sortOrder: "ASC", id: "ASC" },
    });

    // 如果没有配置，返回空列表（不再回退硬编码）
    if (!rows || rows.length === 0) return [];

    // 转换为前端期望格式
    const list: VipPrivilegeItem[] = rows.map((r) => {
      let id = 0;
      if (r.type === 1)
        id = r.itemId || r.id; // 物品优先用 itemId；无则回退配置主键
      else if (r.type === 3 || r.type === 4) id = r.id; // 宝石/副将使用配置主键，便于唯一判定
      return {
        id,
        state: 0,
        title: r.title,
        type: r.type,
        ...(r.choose ? { choose: r.choose } : {}),
      } as VipPrivilegeItem;
    });
    return list;
  }

  private getNextExpRequirement(lvl: number): number {
    // 简化：返回文档示例数值，默认 100
    if (lvl <= -1) return 1;
    const table: Record<number, number> = {
      0: 100,
      1: 5000,
      2: 10000,
      3: 20000,
      4: 50000,
      5: 100000,
      6: 150000,
      7: 300000,
      8: 450000,
      9: 750000,
    };
    return table[lvl] ?? 100;
  }

  private getTotalRequiredExp(targetLvl: number): number {
    if (targetLvl <= -1) return 0;
    // 文档口径：此表为达到该 VIP 等级所需的“累计总经验”
    const cumulative: Record<number, number> = {
      0: 100,
      1: 5000,
      2: 10000,
      3: 20000,
      4: 50000,
      5: 100000,
      6: 150000,
      7: 300000,
      8: 450000,
      9: 750000,
    };
    return cumulative[targetLvl] ?? 0;
  }

  // 6103：根据 pid 返回可选择列表
  // 需求变更：当 VIP 条目为“自选副将”（choose=1，type=4），应返回所有“国士(星级1)”候选列表，参考 1102
  async getVipSelectableWear(
    pid: number
  ): Promise<Array<{ id: number; name: string }>> {
    void pid;
    // 返回国士(星级=1)列表，按成长最高排序（t=1），第一页
    try {
      const result =
        await this.deputyGeneralService.getDeputyGeneralsByStarLevel(
          1,
          1,
          0,
          20
        );
      return (result.list || []).map((x: any) => ({ id: x.id, name: x.name }));
    } catch (e) {
      this.logger.warn(
        `getVipSelectableWear fallback due to error: ${String(e)}`
      );
      return [];
    }
  }

  // 6154：领取/应用所选穿戴（自选副将：根据 npcid 生成并发放给玩家）
  async claimVipWear(
    characterId: number,
    payload: { pid: number; npcid: number }
  ): Promise<{ message: string }> {
    const { pid, npcid } = payload || { pid: 0, npcid: 0 };
    if (!npcid || npcid <= 0) {
      throw new Error("npcid 无效");
    }

    // 读取当前VIP等级，并按“各等级各领一次”规则使用 (characterId,lvl) 唯一键
    const vipRow = await this.ensureVipRow(characterId);
    const lvl = Math.max(-1, vipRow.vipLevel ?? -1);

    // 幂等：先写入领取记录（唯一索引：characterId,lvl,pid,type）
    await this.ensureClaimTable();
    const insertRes: any = await this.vipRepository.manager.query(
      `INSERT IGNORE INTO vip_claim_records(characterId,lvl,pid,type,claimed_at) VALUES (?,?,?,?,NOW())`,
      // 关键：对“自选/随机国士”在不同 vipLevel 下应分别可领一次，因此 pid 使用配置主键或入参 pid，确保 (characterId,lvl,pid,type) 唯一
      [characterId, lvl, Number(pid) || 0, 4]
    );

    // MySQL OkPacket: affectedRows==0 表示已存在（已领取）
    const affected = (insertRes &&
      (insertRes.affectedRows ?? insertRes.affectedRow ?? insertRes.insertId
        ? 1
        : 0)) as number;
    if (!affected) {
      return { message: "已领取，请勿重复操作" };
    }

    // 首次插入成功 → 生成副将（若列表满则进入仓库）
    const generated = await this.deputyGeneralService.generateDeputy(
      Number(npcid),
      characterId
    );

    return { message: `领取成功（副将ID=${generated.deputy_id}）` };
  }
}
